#include "YouthManager.h"
#include <QListIterator>
#include <QDomDocument>
#include <QDomNodeList>
#include <QDomElement>
#include <QDomNode>
#include <QFile>
#include <iostream>
#include <QXmlStreamWriter>
#include "RequirementType.h"

YouthManagerPtr YouthManager::m_classPtr = 0;

YouthManagerPtr YouthManager::getInstanceOf()
{   
    if (m_classPtr == 0)
    {
        m_classPtr = new YouthManager();
    }
    
    return m_classPtr;
}

YouthManager::YouthManager(QObject *parent)
    : QObject(parent)
{
}

YouthManager::~YouthManager()
{
}

void YouthManager::WriteToFile(QString datafile)
{
    QFile file(datafile);
    file.open(QIODevice::ReadWrite);
    QXmlStreamWriter stream(&file);
    stream.setAutoFormatting(true);
    
    stream.writeStartDocument();
    stream.writeStartElement("Ward");
    stream.writeAttribute("name", "Power Ranch 1st");
    foreach(YouthPtr youth, m_youthList)
    {
        stream.writeStartElement("Youth");
        stream.writeTextElement("Name", youth->name());
        stream.writeTextElement("Quorum", QuorumType::NameOf(youth->quorum()));
        stream.writeTextElement("Phone", youth->phoneNumber());
        stream.writeTextElement("Birthdate", youth->birthdate().toString(Qt::ISODate));
        stream.writeTextElement("Address", youth->address());
        
        stream.writeStartElement("Requirements");
        for (QuorumType::Type quorum = QuorumType::Deacon;
             quorum <= QuorumType::Priest; quorum++)
        {
        	
        	if (quorum != QuorumType::Deacon) break;
        	
        	stream.writeStartElement(QuorumType::NameOf(quorum));
        	
        	
        	for (RequirementType::Type group = RequirementType::FIRST;
        	     group <= RequirementType::LAST; 
        	     ++group)
        	{
            	stream.writeStartElement(RequirementType::NameOf(group));
            	for (int i = 1; i <= RequirementsGroup::MAX; ++i)
            	{
            		if (youth->requirements(quorum).requirements(group).requirement(i) > 0)
            		{
            			QString name = QString("Requirement_%1").arg(i);
            			QString value = QString("%1").arg(youth->requirements(quorum).requirements(group).requirement(i));
            			stream.writeTextElement(name, value);
            		}
            	}
            	stream.writeEndElement();
        		
        	}
       	
        	stream.writeEndElement();
        }
        stream.writeEndElement();
        
        stream.writeEndElement();
    }
    stream.writeEndElement();
    stream.writeEndDocument();
}

void YouthManager::LoadFromFile(QString datafile)
{
    QFile file(datafile);
    file.open(QIODevice::ReadOnly);
    QString xml(QString(file.readAll()));

    QDomDocument doc;
    doc.setContent(xml);
    
    QDomElement docElem = doc.documentElement();
    
    QDomNodeList youthList = docElem.childNodes();
    std::cout << "A total of " << youthList.count() << " youth." << std::endl;
    for (int i = 0; i < youthList.count(); ++i) 
    {
        QDomNode youth = youthList.at(i);
        
        // create a new youth object
        YouthPtr y = new Youth();
        m_youthList.append(y);
        
        QDomNodeList attributes = youth.childNodes();
        for (int j = 0; j < attributes.count(); ++j)
        {
            QDomNode attribute = attributes.at(j);
            QDomElement element = attribute.toElement();
            
            if (!element.isNull())
            {
//                if (element.tagName() != "Youth")
//                    break;
                
                QString att = element.tagName();
                if (att.compare("Name", Qt::CaseInsensitive) == 0)
                {
                    y->setName(element.text());
                    std::cout << "Youth Name: " << y->name().toStdString() << std::endl;
                }
                else if (att.compare("Quorum", Qt::CaseInsensitive) == 0)
                {
                    QuorumType::Type q = QuorumType::ValueOf(element.text());
                    y->setQuorum(q);
                }
                else if (att.compare("Birthdate", Qt::CaseInsensitive) == 0)
                {
                    QDate date = QDate::fromString(element.text(), Qt::ISODate);
                    y->setBirthdate(date);
                }
                else if (att.compare("Phone", Qt::CaseInsensitive) == 0)
                {
                    y->setPhoneNumber(element.text());
                }
                else if (att.compare("Address", Qt::CaseInsensitive) == 0)
                {
                    y->setAddress(element.text());
                }
                else if (att.compare("QuorumEntryDate", Qt::CaseInsensitive) == 0)
                {
                    QDate date = QDate::fromString(element.text(), Qt::ISODate);
                    y->setQuorumEntryDate(date);
                }
                else if (att.compare("Requirements", Qt::CaseInsensitive) == 0)
                {
                    QDomNodeList quorums = attribute.childNodes();
                    for (int k = 0; k < quorums.count(); ++k)
                    {
                        QDomNode quorum = quorums.at(k);
                        QDomElement element = quorum.toElement();
                        if (!element.isNull())
                        {
                            QuorumType::Type q = QuorumType::ValueOf(element.tagName());
                            switch (q)
                            {
                            case QuorumType::Deacon:
                            {
                                QDomNodeList groups = quorum.childNodes();
                                for (int l = 0; l < groups.count(); ++l)
                                {
                                    QDomElement element = groups.at(l).toElement();
                                    if (!element.isNull())
                                    {
                                    	RequirementType::Type type = RequirementType::ValueOf(element.tagName());
                                    	LoadRequirements(& y->deacons().requirements(type), groups.at(l));
                                    }
                                }
                                
                            }
                            break;
                            case QuorumType::Teacher:
                                break;
                            case QuorumType::Priest:
                                break;
                            case QuorumType::Retired:
                                break;
                            }
                        }
                    }
                }
            }
        }
    }

    emit youthListUpdated(); 
}

void YouthManager::clear()
{
	foreach(YouthPtr youth, m_youthList)
	{
		delete youth;
	}
	m_youthList.clear();
	emit youthListUpdated();
}

void YouthManager::LoadRequirements(RequirementsGroup* group, QDomNode node)
{
    QDomNodeList requirements = node.childNodes();
    for (int i = 0; i < requirements.count(); ++i)
    {
        QDomNode requirement = requirements.at(i);
        QDomElement element = requirement.toElement();
        if (!element.isNull())
        {
            QString requirementname = element.tagName();
            int num = requirementname.remove("Requirement_").toInt();
            int percent = element.text().toInt();
            group->setReq(num, percent);
        }
    }
}

QList<YouthPtr> YouthManager::quorum(QuorumType::Type theQuorum)
{
    QList<YouthPtr> youthList;
    QListIterator<YouthPtr> i(m_youthList);
    while(i.hasNext())
    { 
        YouthPtr thisYouth = i.next();
        if (thisYouth->quorum() == theQuorum)
            youthList << thisYouth;
    }
    return youthList;   
}

YouthPtr YouthManager::findYouth(QString name)
{
    YouthPtr val = NULL;
    QListIterator<YouthPtr> i(m_youthList);
    while(i.hasNext())
    { 
        YouthPtr thisYouth = i.next();
        if (thisYouth->name().contains(name, Qt::CaseInsensitive))
            val = thisYouth;
    }
    return val;
}

void YouthManager::newDeacon()
{
    YouthPtr youth = new Youth();
    QString name("NewDeacon_%1");
    for (int i = 1; i < 1000; ++i)
    {
    	
    	if (findYouth(name.arg(i)) == NULL)
    	{
    		name = name.arg(i);
    		break;
    	}
    }
    youth->setName(name);
    youth->setQuorum(QuorumType::Deacon);
    m_youthList << youth;
    
    emit youthListUpdated(); 
}

void YouthManager::newTeacher()
{
    YouthPtr youth = new Youth();
    QString name("NewTeacher_%1");
    for (int i = 1; i < 1000; ++i)
    {
    	if (findYouth(name.arg(i)) == NULL)
    	{
    		name = name.arg(i);
    		break;
    	}
    }
    youth->setName(name);
    youth->setQuorum(QuorumType::Teacher);
    m_youthList << youth;
    
    emit youthListUpdated(); 
}

void YouthManager::newPriest()
{
    YouthPtr youth = new Youth();
    QString name("NewPriest_%1");
    for (int i = 1; i < 1000; ++i)
    {
    	if (findYouth(name.arg(i)) == NULL)
    	{
    		name = name.arg(i);
    		break;
    	}
    }
    youth->setName(name);
    youth->setQuorum(QuorumType::Priest);
    m_youthList << youth;
    
    emit youthListUpdated(); 
}

void YouthManager::generateYouthForDebug()
{
    YouthPtr youth1 = new Youth();
    youth1->setName("Deacon #1");
    youth1->setQuorum(QuorumType::Deacon);
    m_youthList << youth1;

    YouthPtr youth2 = new Youth();
    youth2->setName("Deacon #2");
    youth2->setQuorum(QuorumType::Deacon);
    m_youthList << youth2;

    YouthPtr youth3 = new Youth();
    youth3->setName("Deacon #3");
    youth3->setQuorum(QuorumType::Deacon);
    m_youthList << youth3;

    YouthPtr youth4 = new Youth();
    youth4->setName("Teacher #1");
    youth4->setQuorum(QuorumType::Teacher);
    m_youthList << youth4;

    YouthPtr youth5 = new Youth();
    youth5->setName("Teacher #2");
    youth5->setQuorum(QuorumType::Teacher);
    m_youthList << youth5;

    YouthPtr youth6 = new Youth();
    youth6->setName("Priest #1");
    youth6->setQuorum(QuorumType::Priest);
    m_youthList << youth6;

    YouthPtr youth7 = new Youth();
    youth7->setName("Priest #2");
    youth7->setQuorum(QuorumType::Priest);
    m_youthList << youth7;

}
